#include <iostream>
#include <string>
#include <functional>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "Log.hpp"
#include "InetAddr.hpp"

const static int defaultsockfd = -1;

const static int gbacklog = 16;

enum
{
    SOCKET_ERROR = 1,
    BIND_ERROR,
    USAGE_ERROR,
    LISTEN_ERROR
};

class TcpServer;

class ThreadData
{
public:
    ThreadData(int fd, InetAddr addr, TcpServer *s):sockfd(fd), clientaddr(addr), self(s)
    {}
public:
    int sockfd;
    InetAddr clientaddr;
    TcpServer *self;
};

using task_t = std::function<void()>;

class TcpServer
{
public:
    TcpServer(uint16_t port):_port(port),_listensockfd(defaultsockfd)
    {
        
    }
    void InitServer()
    {
        // 1. 创建套接字
        _listensockfd = socket(AF_INET, SOCK_STREAM, 0);
        if(_listensockfd < 0)
        {
            LOG(FATAL,"socket error");
            exit(SOCKET_ERROR);
        }
        LOG(INFO,"socket create success, listensockfd: %d\n",_listensockfd);
        // 2. 绑定套接字bind
        struct sockaddr_in local;
        memset(&local,0,sizeof(local));   
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY;

        int n=::bind(_listensockfd,(struct sockaddr*)&local,sizeof(local));
        if(n<0)
        {
            LOG(FATAL, "bind error");
            exit(BIND_ERROR);
        }
        LOG(INFO,"bind success, port: %d\n",_port);
        // 3. TCP面向连接通信之前建立连接
        n=::listen(_listensockfd,gbacklog);
        if(n<0)
        {
            LOG(FATAL, "listen error");
            exit(LISTEN_ERROR);
        }
        LOG(DEBUG,"listen success, listensockfd: %d\n",_listensockfd);
    }

    void Service(int sockfd,InetAddr client)
    {
        LOG(DEBUG,"get a new connection, sockfd: %d, ip: %s, port: %d\n",sockfd,client.Ip().c_str(),client.Port());
        std::string clientaddr="["+client.Ip()+"]:"+std::to_string(client.Port());
        while(true)
        {
            char inbuffer[1024];
            ssize_t n=read(sockfd,inbuffer,sizeof(inbuffer)-1);
            if(n>0)
            {
                inbuffer[n]=0;
                LOG(DEBUG,"%s# %s\n",clientaddr.c_str(),inbuffer);
                std::string echo_string="[server echo]"+std::string(inbuffer);
                write(sockfd,echo_string.c_str(),echo_string.size());
            }
            else if(n==0)
            {
                LOG(DEBUG,"%s# quit\n",clientaddr.c_str());
                break;
            }
            else
            {
                LOG(ERROR,"%s# read error\n",clientaddr.c_str());
                break;
            }
        }
        ::close(sockfd);
    }

    static void *HandlerSock(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(args);
        td->self->Service(td->sockfd, td->clientaddr);
        delete td;
        return nullptr;
    }

    void Loop()
    {
        _isrunning=true;
        while(_isrunning)
        {
            struct sockaddr_in peer;
            socklen_t len=sizeof(peer);
            int sockfd=::accept(_listensockfd,(struct sockaddr*)&peer,&len);
            if(sockfd<0)
            {
                LOG(WARNING,"accept error");
                continue;
            }
            LOG(INFO,"accept success, sockfd: %d, ip: %s, port: %d",sockfd,inet_ntoa(peer.sin_addr),ntohs(peer.sin_port));
            //Version 0
            //Service(sockfd,InetAddr(peer));
            //Version 1.0
            // pid_t pid=fork();
            // if(pid==0)
            // {
            //     //子进程负责服务
            //     ::close(_listensockfd);
            //     if(fork()>0)
            //     {
            //         exit(0);
            //     }
            //     Service(sockfd,InetAddr(peer));//孙子进程负责服务
            //     exit(0);
            // }
            // //父进程负责等待子进程退出
            // ::close(sockfd);
            // waitpid(pid,nullptr,0);
            // version 2: 采用多线程
            pthread_t t;
            ThreadData *td = new ThreadData(sockfd, InetAddr(peer), this);
            pthread_create(&t, nullptr, HandlerSock, td); //将线程分离
            // vesion 3: 采用线程池
            // task_t t = std::bind(&TcpServer::Service, this, sockfd, InetAddr(peer));
            // ThreadPool<task_t>::GetInstance()->Enqueue(t);
        }
        _isrunning=false;
    }
    ~TcpServer()
    {
        if(_listensockfd>defaultsockfd)
        {
            ::close(_listensockfd);
        }
        _listensockfd=defaultsockfd;
    }
    private:
        uint16_t _port;
        int _listensockfd;
        bool _isrunning; 
};
